<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON相关</title>
    <script src="../../lib/vue-2.6.12.js"></script>
</head>
<body>
    <div id="app">
        <div>

            <h1>JSON.stringify()和JSON.parse()的奇思妙用</h1>
            <pre>源于： https://www.cnblogs.com/IwishIcould/p/17319008.html </pre>


            <h2>一、JSON.stringify()详解</h2>
            <pre>
                语法： 
                    JSON.stringify(value[, replacer [, space]])

                value: 将要序列化成 一个JSON 字符串的值。

                replacer 可选: 如果该参数是一个函数，则在序列化过程中，被序列化的值的每个属性都会经过该函数的转换和处理；如果该参数是一个数组，则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中；如果该参数为null或者未提供，则对象所有的属性都会被序列化。
                
                space 可选: 指定缩进用的空白字符串，用于美化输出（pretty-print）；如果参数是个数字，它代表有多少的空格；上限为10。该值若小于1，则意味着没有空格；如果该参数为字符串(字符串的前十个字母)，该字符串将被作为空格；如果该参数没有提供（或者为null）将没有空格。
                
                返回值 节:  一个表示给定值的JSON字符串。



                JSON.stringify()将值转换为相应的JSON格式：
               - 转换值如果有toJSON()方法，该方法定义什么值将被序列化。
               - 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
               - 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
               - undefined、任意的函数以及 symbol 值，在序列化过程中会被忽略（出现在非数组对象的属性值中时）或者被转换成 null（出现在数组中时）。函数、undefined被单独转换时，会返回undefined，如JSON.stringify(function(){}) or JSON.stringify(undefined).
               - 对包含循环引用的对象（对象之间相互引用，形成无限循环）执行此方法，会抛出错误。
               - 所有以 symbol 为属性键的属性都会被完全忽略掉，即便 replacer 参数中强制指定包含了它们。
               - Date日期调用了toJSON()将其转换为了string字符串（同Date.toISOString()），因此会被当做字符串处理。
               - NaN和Infinity格式的数值及null都会被当做null。
               - 其他类型的对象，包括Map/Set/weakMap/weakSet，仅会序列化可枚举的属性。


            </pre>



            <h3>1.JSON.stringify(obj)转换的值对象obj中有toJSON()方法时，辣么toJSON()的返回值直接替代当前obj这个对象</h3>
            <pre>
                场景1：被转化的对象obj中有toJSON()方法，该方法且有返回值

                var obj = {
                    name: '张三',
                    like: '喜欢养鸟和狗',
                    toJSON: function() {

                        return "无人应答"
                    }
                };

                var newStr = JSON.stringify(obj);
                console.log(newStr)

                输出内容是： {{newStr()}} // "无人应答"

                解析：
                因为obj对象中有 toJSON()方法，那么这个方法的返回值将直接替代这个obj对象。

            </pre>

            <pre>
            ************************************

               场景2：被转化的对象obj中有toJSON()方法，但该方法无返回值
                
               
               var obj2 = {
                    name: '张三',
                    like: '喜欢养鸟和狗',
                    toJSON: function() {

                        console.log("没有返回值")
                    }
                };

                var newStr = JSON.stringify(obj2);
                console.log(newStr)

                输出内容是： {{newStr2()}}    // undefined

                解析：
                因为toJSON()函数没有返回值时，默认返回 undefined

            </pre>

            <pre>
            ************************************

                场景3：对象中不可枚举的值将不会被序列化

                var obj2 = {
                    name: '张三',
                    like: '喜欢养鸟和狗'
                };

                Object.defineProperty(obj2, 'name', {
                    value: '张小三',
                    enumerable: false //将它设置为不可枚举
                })

                // name属性不可枚举了，将不会被序列化
                var str = JSON.stringify(obj2);
                console.log(str)

                输出内容是： {{serializeNoEnumerableObj()}}

            ************************************

                场景4：无法序列化错误对象 Error，错误对象将会被转化为空对象
                
                const err = new Error('我是错误对象')

                let obj = {
                    name: '张三',
                    like: '喜欢养鸟和狗',
                    err
                }

                var str = JSON.stringify(obj);
                console.log(str)

                输出内容是： {{serializeErrorObj()}}  // {"name":"张三","like":"喜欢养鸟和狗","err":{}}

                
            ************************************
                如何序列化Error对象呢？

                const err = new Error('我是错误对象')

                //1. 获取一个对象的所有属性的方法是： `Object.getOwnPropertyNames(obj)`
                let errorPropertyArray = Object.getOwnPropertyNames(err)

                //错误对象的属性：
                // name属性：       错误类型；
                // message属性：    错误相关的描述信息；
                // stack 属性：     函数调用栈记录信息（错误相关信息，错误出现的位置） 
                
                console.log("Error对象的所有的属性：", errorPropertyArray) // stack message
                
                //2. 利用JSON.stringify(value[, replacer [, space]])的第二个参数特性来序列化obj对象
                let obj = {
                    name: '张三',
                    like: '喜欢养鸟和狗',
                    err
                }

                var objPropertyArray = Object.getOwnPropertyNames(obj)
                console.log("obj对象的所有属性：", objPropertyArray) // name like err

                objPropertyArray.push.apply( objPropertyArray, errorPropertyArray) // 拼接出新的属性数组
                console.log("obj对象的所有属性：", objPropertyArray) // name like err stack message

                var str = JSON.stringify(obj, objPropertyArray, 2 );
                console.log(str)

                输出内容是：
                {{serializeErrorObj2()}}
    
            </pre>

            <pre>
            ************************************

            场景5：NaN 和 Infinity 及 null 都会被当做null

                // 1.7976931348623157E+10308 是浮点数的最大上限值 显示为Infinity
                // -1.7976931348623157E+10308 是浮点数的最小下限值 显示为-Infinity
                const obj = {
                    infinityMax: 1.7976931348623157E+10308,
                    infinityMin: -1.7976931348623157E+10308,
                    a: NaN
                }

                var str = JSON.stringify(obj);
                console.log(str)

                输出的内容是： {{serializeNullInfinity()}}

            </pre>

            <pre>
            ************************************

            场景6：日期对象将会对其序列化为字符串string

                var obj = {
                    name: '张三',
                    like: '喜欢养鸟和狗',
                    time: new Date(),
                };
            
                var str = JSON.stringify(obj);
                console.log(str)
                
                const objCopy = JSON.parse(str)
                console.log('类型是： ',  typeof objCopy.time) // string

                输出的内容是： {{serializeDateObj()}}

            </pre>

            <pre>
            ************************************
            undefined、函数、symbol值，在不同的场合将会发生不同的反应


            场景7：undefined、函数、symbol值，在非数组对象的属性值中时序列化会被忽略
                let person = Symbol('张三')
                const obj = {
                    person,
                    un: undefined,
                    funSy: () => {console.log('小不点儿...')}
                }
                
                const str = JSON.stringify(obj)
                console.log(str)

                const objCopy = JSON.parse(str)
                console.log(objCopy)

                输出内容是：{{serializeFuc1()}}


            
            场景8：undefined、函数、symbol值，在数组对象的属性值中时序列化会被换成null
                let person = Symbol('张三')
                let sayFun = function () {console.log('小不点儿...')}
                let arr = [undefined, person, sayFun]
                
                const str = JSON.stringify(arr)
                console.log(str)

                const objCopy = JSON.parse(str)
                console.log(objCopy)

                输出内容是：{{serializeFuc2()}}

            场景9：undefined、函数、symbol值，在单独被序列化时会返回 undefined
                console.log(JSON.stringify(Symbol('张三')))
                console.log(JSON.stringify(function () {console.log('小不点儿...')}))
                console.log(JSON.stringify(undefined))
                
                输出内容是：{{serializeFuc3()}} // 都是 undefined
        
            </pre>

            <h3>二、JSON.parse()详解</h3>
            <pre>
            语法：
                JSON.parse(jsonStr,[function])
            
                jsonStr：必须参数；一个有效的 JSON字符串。
                function：选填；一个转换结果的函数，将为对象的每个成员调用此函数。
            
                ************************************
                
                JSON是一种纯数据格式，它只包含属性，没有方法；也不允许使用逗号作为结尾。
                JSON数据格式为键值对。必须使用双引号进行包裹，否则会报错。
                

                // JSON字符串使用 单引号，
                let jsonStr = "{'name': '张三', 'sex': '男'}"
                let newArr = JSON.parse(jsonStr)
                console.log(newArr)
                输出结果：{{jsonFunc1()}} // 报错：Expected property name or '}' in JSON at position 1
            
                // JSON字符串使用 双引号，
                let jsonStr = '{"name":"张三", "sex":"男"}'
                let newArr = JSON.parse(jsonStr)
                console.log(newArr)
                输出结果：{{jsonFunc2()}}
                
            </pre>
        </div>
    </div>

    <script>

        let vm = new Vue({
            el: '#app',
            data: {
                
            },
            methods: {
                newStr(){
                    var obj = {
                        name: '张三',
                        like: '喜欢养鸟和狗',
                        toJSON: function() {

                            return "无人应答"
                        }
                    };
                
                    var str = JSON.stringify(obj);
                    console.log(str)
                    return str
                },

                newStr2(){
                    var obj2 = {
                        name: '张三',
                        like: '喜欢养鸟和狗',
                        toJSON: function() {

                            console.log("没有返回值")

                        }
                    };

                    var str = JSON.stringify(obj2);
                    console.log(str)
                    return str
                },

                serializeErrorObj() {
                    const err = new Error('我是错误对象')

                    let obj = {
                        name: '张三',
                        like: '喜欢养鸟和狗',
                        err
                    }

                    var str = JSON.stringify(obj);
                    console.log(str)
                    return str
                },
                
                serializeErrorObj2() {
                    const err = new Error('我是错误对象')

                    //1. 获取一个对象的所有属性的方法是： `Object.getOwnPropertyNames(obj)`
                    let errorPropertyArray = Object.getOwnPropertyNames(err)

                    //错误对象的属性：
                    // name属性：       错误类型；
                    // message属性：    错误相关的描述信息；
                    // stack 属性：     函数调用栈记录信息（错误相关信息，错误出现的位置） 
                    
                    console.log("Error对象的所有的属性：", errorPropertyArray) // stack message
                    
                    //2. 利用JSON.stringify(value[, replacer [, space]])的第二个参数特性来序列化obj对象
                    let obj = {
                        name: '张三',
                        like: '喜欢养鸟和狗',
                        err
                    }

                    var objPropertyArray = Object.getOwnPropertyNames(obj)
                    console.log("obj对象的所有属性：", objPropertyArray) // name like err

                    objPropertyArray.push.apply( objPropertyArray, errorPropertyArray) // 拼接出新的属性数组
                    console.log("obj对象的所有属性：", objPropertyArray) // name like err stack message

                    var str = JSON.stringify(obj, objPropertyArray, 2 );
                    console.log(str)
                    return str
                },

                serializeNoEnumerableObj() {
                    var obj2 = {
                        name: '张三',
                        like: '喜欢养鸟和狗'
                    };

                    Object.defineProperty(obj2, 'name', {
                        value: '张小三',
                        enumerable: false //将它设置为不可枚举
                    })

                    // name属性不可枚举了，将不会被序列化
                    var str = JSON.stringify(obj2);
                    console.log(str)
                    return str
                },

                serializeNullInfinity() {
                    // 1.7976931348623157E+10308 是浮点数的最大上限值 显示为Infinity
                    // -1.7976931348623157E+10308 是浮点数的最小下限值 显示为-Infinity
                    const obj = {
                        infinityMax: 1.7976931348623157E+10308,
                        infinityMin: -1.7976931348623157E+10308,
                        a: NaN
                    }

                    var str = JSON.stringify(obj);
                    console.log(str)
                    return str; 

                },

                serializeDateObj() {
                    var obj = {
                        name: '张三',
                        like: '喜欢养鸟和狗',
                        time: new Date(),
                    };
                
                    var str = JSON.stringify(obj);
                    console.log(str)
                    
                    const objCopy = JSON.parse(str)
                    console.log('类型是： ',  typeof objCopy.time)

                    return str
                },

                serializeFuc1() {
                    let person = Symbol('张三')
                    const obj = {
                        person,
                        un: undefined,
                        funSy: () => {console.log('小不点儿...')}
                    }
                    
                    const str = JSON.stringify(obj)
                    console.log(str)

                    const objCopy = JSON.parse(str)
                    console.log(objCopy)

                    return str
                },

                serializeFuc2() {
                    let person = Symbol('张三')
                    let sayFun = function () {console.log('小不点儿...')}
                    let arr = [undefined, person, sayFun]
                    
                    const str = JSON.stringify(arr)
                    console.log(str)

                    const objCopy = JSON.parse(str)
                    console.log(objCopy)

                    return str
                },

                serializeFuc3() {
                    console.log(JSON.stringify(Symbol('张三')))
                    console.log(JSON.stringify(function () {console.log('小不点儿...')}))
                    console.log(JSON.stringify(undefined))

                },

                jsonFunc1() {

                    try {

                        // JSON字符串使用 单引号，
                        let jsonStr = "{'name': '张三', 'sex': '男'}"
                        let newArr = JSON.parse(jsonStr)
                        console.log(newArr)

                    } catch (error) {
                       console.log(error.message) 
                    }
                },

                jsonFunc2() {

                    // JSON字符串使用 双引号，
                    let jsonStr = '{"name":"张三", "sex":"男"}'
                    let newArr = JSON.parse(jsonStr)
                    console.log(newArr)
                },

            },

        })

        



    </script>
</body>
</html>